home *** CD-ROM | disk | FTP | other *** search
Text File | 1988-08-16 | 15.0 KB | 359 lines | [TEXT/MPS ] |
- {------------------------------------------------------------------------------
- #
- # Apple Macintosh Developer Technical Support
- #
- # MacApp Color QuickDraw Fractal Sample Application
- #
- # FracApp
- #
- # UFracApp.p - Pascal Source
- #
- # Copyright © 1988 Apple Computer, Inc.
- # All rights reserved.
- #
- # Versions: 1.0 8/88
- #
- # Components: MFracApp.p August 1, 1988
- # UFracApp.p August 1, 1988
- # UFracApp.inc1.p August 1, 1988
- # FracApp.r August 1, 1988
- # FracApp.make August 1, 1988
- #
- # This is a program to calculate the Mandelbrot set, allowing you to zoom in on areas
- # that are selected with the mouse. There are some special color tricks played
- # in order to make the program more jazzy. A special color table is used to give
- # smooth transitions from one color to the next. Color table animation is also
- # supported, for the wowem effect of flowing Mandelbrot images.
- # The program is written in MacApp 1.1, which explains why it has a real user
- # interface. Mandelbrot images take about 30 minutes to calculate. It is
- # Juggler aware so you can put the program in the background where it will
- # continue to calculate, while you do something more important, like look at
- # the source code. It also handles multiple documents, and reading/writing of
- # PICT files using the bottlenecks to minimize the memory hit.
- #
- # This program is intended to be a real world example of handling color in a
- # nontrivial fashion. As such it has some rather special color requirements,
- # and those don’t match the current system architecture very well. The program
- # is designed to be compatible with the future, it will not break in future
- # systems. However, it does not use the Palette Manager, which means that
- # there will be situations where the colors will not look right in either FracApp
- # or another program running under MultiFinder. The approach that FracApp
- # uses is thus not the preferred Apple approach and does NOT have the Apple
- # seal of approval from engineering. The only way to get the stamp of approval
- # is to use the Palette Manager. To do a program of this form, you cannot
- # use the Palette Manager without some extra hacks that are compatibility
- # risks in themselves. So... use at your own risk. If you are forced to revise your
- # program because you followed this as an example, you cannot gripe to Apple, since
- # it is not fully approved. You just have to change your program, which I hope is no
- # big deal. You can give this code to other people, as long as they recognize
- # that it is not fully approved too.
- #
- # Unless you have very special color requirements, you should use the Palette
- # Manager. It works for most things, and is much easier to use than the
- # approach taken here. There are a few things it won’t do of course, leading
- # to this code. If you can do it, use the Palette Manager and save yourself
- # some grief.
- # Written in MacApp Object Pascal code.
- # Compatibility rating = 2. (nothing will break, but it may not
- # always look correct.)
- #
- ------------------------------------------------------------------------------}
- {Copyright 1988 by Bob. All rights reserved, since Bob has all rights.
- February 1, 1988.
- Written by Bo3b Johnson of Developer Technical Support. }
-
- UNIT UFracApp;
-
- (*
-
- This is a not too small application which can calculate a fractal in full color
- on the Mac II, using direct 881 code for speed. It saves files on disk as PICT.
- For full info, see the implementation file.
-
- *)
-
- INTERFACE
-
- USES
- {$LOAD FracApp881.LOAD}
- MemTypes, QuickDraw, OSIntf, ToolIntf, PackIntf,
- UObject, UList, UMacApp,
- PaletteMgr, UPrinting;
- {$LOAD}
-
- CONST
-
- {Command numbers}
-
- kSignature = 'Arf '; {Application signature}
- kFileType = 'PICT'; {File-type code used for document files
- created by this application}
- kFracAppWindowID = 1001; {This is passed to NewSimpleWindow as the
- resource ID of the the WIND Resource
- which defines the window for this
- application's documents}
- kStaggerAmount = 30;
- kPICTHeaderSize = 512; { 512 bytes off the file are used for our info and print info. }
- kSelPattern = 128; { pattern resource Id. }
- kNewFractal = 1000; { item Id for New Fractal menu option. }
- kRotateColors = 1001; { item Id for Rotate Colors menu option in Fractal menu. }
- kClut = 501; { Res Id for the clut resource that we use for offscreen. }
- kNumColors = 195; { number of colors we animate, and use in calculation. }
- kNumPalette = 14; { 14 extra colors in system palette at end of colors. }
- kWrongMachine = 1000; { error code if we cannot run, from ForceEnvirons. }
- kBadRotate = $044C0002; { message code to use STR# 1100, string 2. }
-
- envDontCare = 0; { don't care is always 0, for ForceEnvirons. }
-
- TYPE
- { The header record for each of the files saved by FracApp. This header includes the
- pertinent data that allows a fractal to be restarted, as well as displayed
- on the screen. The print record follows this info in the first 512 bytes of a file,
- but that info is read by the standard DoRead/DoWrite methods. Some of the fields
- are LongInts to avoid rounding errors during calculations. }
- FracRecord = RECORD
- fType: OSType; { 4 set as 'Arf ' for these documents. }
- hdrId: Integer; { 2 as 'FA' FracApp header ID. }
- version: Integer; { 2 file version decides type of file. }
- done: Boolean; { 2 if the fractal is finished or not. }
- realMin: Extended; { 12 minimum value of fractal on real/p axis. }
- realMax: Extended; { 12 maximum value of fractal on real/p axis. }
- imagMin: Extended; { 12 minimum on imaginary/q axis. }
- imagMax: Extended; { 12 maximum on imaginary/q axis. }
- deltaP: Extended; { 12 horizontal step size in fractal space. }
- deltaQ: Extended; { 12 vertical step size in fractal space. }
- plotWidth: LongInt; { 4 width of fractal area in pixels. }
- plotHeight: LongInt; { 4 height of fractal area in pixels. }
- calcRect: Rect; { 8 rectangle surrounding the window it was built for. }
- curRow: LongInt; { 4 counter for current pixel position to be done. Vertical. }
- curCol: LongInt; { 4 counter for current pixel. Horizontal. }
- elapsedTime: LongInt; { 4 amount of time to do this fractal in seconds. }
- END; { FracRecord. }
-
-
-
- {------------------------------- Application -------------------------------}
-
- TFracAppApplication = OBJECT(TApplication)
-
-
- PROCEDURE TFracAppApplication.IFracAppApplication (itsMainFileType: OSType);
- {Initializes the application and globals.}
-
- FUNCTION TFracAppApplication.DoMakeDocument(
- itsCmdNumber: CmdNumber): TDocument; OVERRIDE;
- {Launches a TFracAppDocument; called when application's icon is
- opened, and when New or Open is requested by the user.
- Every application which uses Documents MUST override this
- method}
-
- PROCEDURE TFracAppApplication.DoIdle (Phase: IdlePhase); OVERRIDE;
- { Performs Idle time processing for the application. This will do the
- fractal calculation during the idle times. It will allow each open
- view a chance to calculate. }
-
- PROCEDURE TFracAppApplication.DoSetupMenus; OVERRIDE;
- { Set up the menus choice in Fractal Menu to handle Rotate Colors. }
-
- FUNCTION TFracAppApplication.DoMenuCommand(
- aCmdNumber: CmdNumber): TCommand; OVERRIDE;
- { Handle the menu choice out of the Fractal Menu for Rotate Colors. }
-
- PROCEDURE TFracAppApplication.RegainControl(checkClipboard: BOOLEAN);
- OVERRIDE;
- { When we are switched in we need to reset the color table. }
-
- PROCEDURE TFracAppApplication.AboutToLoseControl(convertClipboard: BOOLEAN);
- OVERRIDE;
- { When we are switched out we need to restore the color table to be polite. }
-
- END; { TFracAppApplication }
-
-
- {------------------------------- Document -------------------------------}
-
- TFracAppDocument = OBJECT(TDocument)
-
- { Now the fields that are special to the fractal itself. These are the
- variables that make up the display state and the definition of the
- fractal itself. They are associated with the document so they can
- be stored in a file, and read back in. Essentially a global state for
- each fractal document. }
-
- fFracHeader: FracRecord; { global state on fractal. }
- fStartTime: LongInt; { starting time of calculations. }
- fBigBuff: Ptr; { pointer to offscreen data }
- fDrawingDevice: GDHandle; { handle to our offscreen gDevice. }
- fDrawingPort: CGrafPtr; { pointer to drawing buffer. }
-
- fFracAppView: TFracAppView;
- {Every document object must preserve references to all the views it
- creates as fields of the document object, since DoMakeWindows
- will need to know which views to install in the windows it
- creates}
-
-
- PROCEDURE TFracAppDocument.BuildOffWorld (sizeOfDoc: Rect);
- { Allocates offscreen gDevice and port for document data. }
-
- PROCEDURE TFracAppDocument.SetUpConstants;
- { Sets up starting constants for calculation. }
-
- PROCEDURE TFracAppDocument.IFracAppDocument;
- {Init routine for the document, sets up the object, then the fractal default state. }
-
- PROCEDURE TFracAppDocument.DoInitialState; OVERRIDE;
- { Does the work for a New operation, where we start with a new fractal
- that doesn't have any stored data. This is set up the view with no
- data and set up the fractal coordinates to the default. }
-
- PROCEDURE TFracAppDocument.DoMakeWindows; OVERRIDE;
- {Launches the window which will represent the document on the
- screen. Every document which has any screen display MUST
- override this method}
-
- PROCEDURE TFracAppDocument.DoMakeViews(forPrinting: BOOLEAN); OVERRIDE;
- {Launches the view which is seen in the document's window. Every
- document which has any screen display or which can be printed
- MUST override this method}
-
- PROCEDURE TFracAppDocument.DoNeedDiskSpace(VAR dataForkBytes,
- rsrcForkBytes: LONGINT); OVERRIDE;
- { Finds out the entire size of the object to be saved into the file so that the
- correct amount of disk space can be used. }
-
- PROCEDURE TFracAppDocument.DoRead(aRefNum: INTEGER; rsrcExists,
- forPrinting: BOOLEAN); OVERRIDE;
- { Reads in the data out of the data fork of the file, and stows it into the
- document’s bitMap. Also resets the vars in the document object to match
- the saved values from the header. }
-
- PROCEDURE TFracAppDocument.DoWrite(aRefNum: INTEGER;
- makingCopy: BOOLEAN); OVERRIDE;
- { Converts the data in the document’s port into a PICT, then writes that block
- out to the file, making it into a standard PICT file. }
-
- PROCEDURE TFracAppDocument.FreeData; OVERRIDE;
- {}
-
- PROCEDURE TFracAppDocument.Free; OVERRIDE;
- { Free method for our document. It disposes the data block of the picture
- data that was read in from the disk, and kills offscreen stuff. }
-
- PROCEDURE TFracAppDocument.CalcCity;
- { Does the idle time calculations for the document. This is for the actual
- fractal calculations. It is called by the handler for the Application
- DoIdle. It is called for all open documents. }
-
- END; { TFracAppDocument }
-
-
-
- {------------------------------- View -------------------------------}
-
- TFracAppView = OBJECT(TView)
-
- { These fields are for the use of the view, and help define our specific view, that
- is the offscreen bitMap representation of the fractal. }
- fSelectionRect: Rect; { rectangle that is current selection }
- fFracAppDocument: TFracAppDocument; { handy to avoid type coercion. }
-
- PROCEDURE TFracAppView.IFracAppView (itsDocument: TFracAppDocument;
- sizeOfView: Rect);
- { Inits the view object itself. }
-
- PROCEDURE TFracAppView.Draw(area: Rect); OVERRIDE;
- {Draws the view seen in the window. Every nonblank view MUST
- override this method}
-
- FUNCTION TFracAppView.DoMenuCommand(
- aCmdNumber: CmdNumber): TCommand; OVERRIDE;
- { Handle the menu choices for New Fractal out of the Fractal Menu. }
-
- PROCEDURE TFracAppView.DoSetupMenus; OVERRIDE;
- { Set up the New Fractal menus choice in Fractal Menu, based on selection. }
-
- FUNCTION TFracAppView.DoMouseCommand(VAR downLocalPoint: Point;
- VAR info: EventInfo;
- VAR hysteresis: Point): TCommand; OVERRIDE;
- { Handle the mouse events in the view. Needs to do the selection of a new
- range for the next fractal to be calculated. }
-
- PROCEDURE TFracAppView.DoHighlightSelection(fromHL, toHL: HLState); OVERRIDE;
- { Highlight the current selection rectangle if there is one. }
-
- END; { TFracAppView }
-
-
- {------------------------------- Command -------------------------------}
-
- TAreaSelector = OBJECT(TCommand)
-
- { These fields are for the command objects that we use. The first one we need
- for sure is the selection object to handle the mouse selection in the content
- region of the view. }
- fOwnerView: TFracAppView;
-
-
- PROCEDURE TAreaSelector.IAreaSelector(ownerView: TFracAppView; startPt: Point);
- { Initialize the selection object itself. This basically sets up with IObject,
- then sets the fSelectionRect to be a minimal rectangle. }
-
- FUNCTION TAreaSelector.TrackMouse(aTrackPhase: TrackPhase;
- VAR anchorPoint, previousPoint, nextPoint: Point;
- mouseDidMove: BOOLEAN): TCommand; OVERRIDE;
- { Track the mouse while the button is down in the view. }
-
- PROCEDURE TAreaSelector.TrackFeedback(anchorPoint, nextPoint: Point;
- turnItOn, mouseDidMove: BOOLEAN); OVERRIDE;
- { Feedback that matches better, using the selection pattern. }
-
- PROCEDURE TAreaSelector.TrackConstrain(anchorPoint, previousPoint: Point;
- VAR nextPoint: Point); OVERRIDE;
- { Constrain the mouse movement to be a rect which matches the screen. }
-
- END; { TAreaSelector }
-
- {------------------------------- GarDevice -------------------------------}
-
- { We also need to keep track of what all gDevices in the system are doing. In order
- to handle this dynamically a TList is a logical choice. The GarDevice objects will
- keep information about each gDevice in the system for use in color handling.
- When used, the Each method will be used to affect every gDevice in the system. }
-
- TGarDevice = OBJECT(TObject)
-
- { The fields for each GarDevice object. }
- fColorTable: CTabHandle;
- fOldSeed: LongInt;
- fDevice: GDHandle;
- fDrawSeed: LongInt;
-
- PROCEDURE TGarDevice.IGarDevice (OwnerGDevice: GDHandle);
- { Initialize the GarDevice object, add it to the TList of GarDevices. }
-
- PROCEDURE TGarDevice.PoundColors;
- { Force the colors on this GarDevice to have the desired color table if possible. }
-
- PROCEDURE TGarDevice.UnPoundColors;
- { Remove our fascist color mapping when we are switched out. Restore to
- what the system was using last. }
-
- PROCEDURE TGarDevice.RotateColors;
- { Rotate the colors on this GarDevice if we can. Animation of colors. }
-
- PROCEDURE TGarDevice.SetUpColorMap;
- { Save off the ctSeed of the gDevice owned by this GarDevice, or set up the
- color search proc to do the zebra fractals if not enough colors. }
-
- PROCEDURE TGarDevice.RemoveColorMap;
- { Restore the ctSeed of the gDevice, or remove the color search proc. }
-
- END; { TGarDevice }
-
- IMPLEMENTATION
-
- {$I UFracApp.inc1.p}
-
- END.
-